package uk.co.q3c.deplan.server.unit.domain.util;

import java.util.ArrayList;

import org.testng.Assert;
import org.testng.annotations.Test;

import uk.co.q3c.deplan.client.domain.dag.ChangeInvalidException;
import uk.co.q3c.deplan.client.domain.dag.CycleDetectedException;
import uk.co.q3c.deplan.client.domain.dag.DAG;
import uk.co.q3c.deplan.client.domain.dag.DAGEdgeChange;
import uk.co.q3c.deplan.client.domain.dag.DAGVertexChange;
import uk.co.q3c.deplan.client.domain.dag.SharedStructureChangeLog;
import uk.co.q3c.deplan.client.domain.dag.Vertex;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;
import uk.co.q3c.deplan.client.domain.task.Task;
import uk.co.q3c.deplan.client.domain.task.BaseTask;
import uk.co.q3c.deplan.server.unit.dao.LocalDatastoreTestCase;

import com.googlecode.objectify.Key;

/**
 * DirectedAcyclicGraph
 * 
 * @author David Sowerby 6 Jul 2010
 * 
 */

@Test
public class DirectedAcyclicGraph_UT extends LocalDatastoreTestCase {

	DAG<Key<? extends Task>> dependencies;
	Task t1;
	Task t2;

	@Override
	protected void beforeMethod() throws Exception {
		super.beforeMethod();
		dependencies = new DAG<Key<? extends Task>>();
		dependencies.setChangeLog(new SharedStructureChangeLog());
		t1 = new BaseTask(connection);
		t2 = new BaseTask(connection);
		t1.save();
		t2.save();
	}

	public <T extends Task> void basicConstruct() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		Vertex<Key<? extends Task>> t1v = dependencies.addVertex(t1.getKey());
		Vertex<Key<? extends Task>> t2v = dependencies.addVertex(t2.getKey());
		// Vertex has the right key
		Assert.assertEquals(t1v.getKey(), t1.getKey());
		Assert.assertEquals(t2v.getKey(), t2.getKey());
		dependencies.addEdge(t1.getKey(), t2.getKey());
		Key<? extends Task> v1k = t1v.getChildren()
				.get(0)
				.getKey();

		Key<? extends Task> v2k = t2.getKey();
		Assert.assertEquals(v1k, v2k);
		dependencies.removeEdge(t1.getKey(), t2.getKey());
		Assert.assertEquals(t1v.getChildren()
				.size(), 0);
	}

	public void transactionHistory() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		dependencies.addVertex(t1.getKey());
		dependencies.addVertex(t2.getKey());

		SharedStructureChangeLog history = dependencies.getChangeLog();
		Assert.assertEquals(history.changeCount(), 2);
		dependencies.addEdge(t1.getKey(), t2.getKey());
		Assert.assertEquals(history.changeCount(), 3);
		dependencies.removeEdge(t1.getKey(), t2.getKey());
		Assert.assertEquals(history.changeCount(), 4);
		dependencies.removeVertex(t1.getKey());
		Assert.assertEquals(history.changeCount(), 5);
		// correct types of change

		// add vertex
		Assert.assertTrue(history.get(0)
				.isAdd());
		Assert.assertTrue((history.get(0)) instanceof DAGVertexChange<?>);

		// add vertex
		Assert.assertTrue(history.get(1)
				.isAdd());
		Assert.assertTrue((history.get(0)) instanceof DAGVertexChange<?>);

		// add edge
		Assert.assertTrue(history.get(2)
				.isAdd());
		Assert.assertTrue((history.get(2)) instanceof DAGEdgeChange<?>);

		// remove edge
		Assert.assertFalse(history.get(3)
				.isAdd());
		Assert.assertTrue((history.get(3)) instanceof DAGEdgeChange<?>);

		// remove vertex
		Assert.assertFalse(history.get(4)
				.isAdd());
		Assert.assertTrue((history.get(4)) instanceof DAGVertexChange<?>);

	}

	public void removeVertexWithEdges() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		dependencies.addVertex(t1.getKey());
		Vertex<Key<? extends Task>> t2v = dependencies.addVertex(t2.getKey());
		dependencies.addEdge(t1.getKey(), t2.getKey());
		Assert.assertEquals(t2v.getParents()
				.size(), 1);
		dependencies.removeVertex(t1.getKey());
		Assert.assertEquals(t2v.getParents()
				.size(), 0);

	}

	/**
	 * check use of equals() with key
	 * 
	 * @throws PersistenceReferenceException
	 */

	public void equals() throws PersistenceReferenceException {
		Key<? extends Task> k1 = t1.getKey();
		Key<? extends Task> k2 = t1.getKey();
		Assert.assertTrue(k1 == k2);
		Assert.assertTrue(k1.equals(k2));
		ArrayList<Key<?>> list = new ArrayList<Key<?>>();
		list.add(k1);
		Assert.assertTrue(list.contains(k2));

	}

}
